﻿using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace Icon
{
    enum ShowWindowCommands : int
    {
        /// <summary>
        /// Hides the window and activates another window.
        /// </summary>
        Hide = 0,
        /// <summary>
        /// Activates and displays a window. If the window is minimized or 
        /// maximized, the system restores it to its original size and position.
        /// An application should specify this flag when displaying the window 
        /// for the first time.
        /// </summary>
        Normal = 1,
        /// <summary>
        /// Activates the window and displays it as a minimized window.
        /// </summary>
        ShowMinimized = 2,
        /// <summary>
        /// Maximizes the specified window.
        /// </summary>
        Maximize = 3, // is this the right value?
        /// <summary>
        /// Activates the window and displays it as a maximized window.
        /// </summary>       
        ShowMaximized = 3,
        /// <summary>
        /// Displays a window in its most recent size and position. This value 
        /// is similar to <see cref="Win32.ShowWindowCommand.Normal"/>, except 
        /// the window is not actived.
        /// </summary>
        ShowNoActivate = 4,
        /// <summary>
        /// Activates the window and displays it in its current size and position. 
        /// </summary>
        Show = 5,
        /// <summary>
        /// Minimizes the specified window and activates the next top-level 
        /// window in the Z order.
        /// </summary>
        Minimize = 6,
        /// <summary>
        /// Displays the window as a minimized window. This value is similar to
        /// <see cref="Win32.ShowWindowCommand.ShowMinimized"/>, except the 
        /// window is not activated.
        /// </summary>
        ShowMinNoActive = 7,
        /// <summary>
        /// Displays the window in its current size and position. This value is 
        /// similar to <see cref="Win32.ShowWindowCommand.Show"/>, except the 
        /// window is not activated.
        /// </summary>
        ShowNA = 8,
        /// <summary>
        /// Activates and displays the window. If the window is minimized or 
        /// maximized, the system restores it to its original size and position. 
        /// An application should specify this flag when restoring a minimized window.
        /// </summary>
        Restore = 9,
        /// <summary>
        /// Sets the show state based on the SW_* value specified in the 
        /// STARTUPINFO structure passed to the CreateProcess function by the 
        /// program that started the application.
        /// </summary>
        ShowDefault = 10,
        /// <summary>
        ///  <b>Windows 2000/XP:</b> Minimizes a window, even if the thread 
        /// that owns the window is not responding. This flag should only be 
        /// used when minimizing windows from a different thread.
        /// </summary>
        ForceMinimize = 11
    }

    public class WindowsHelper
    {
        public static int GwlExstyle = -20;
        public static int WsExAppwindow = 0x40000;

        [DllImport("user32.dll")]
        public static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll")]
        public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindow(string className, string title);

        [DllImport("user32.dll")]
        private static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow);

        [DllImport("user32.dll")]
        private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, int lParam);

        [DllImport("user32.dll")]
        private static extern int GetWindowThreadProcessId(IntPtr hWnd, ref int dwProcessId);

        delegate bool EnumWindowsProc(IntPtr hwnd,int lParam);

        private static IntPtr _targetHwnd;

        private static bool EnumWindowsProcessId(IntPtr hwnd, int lParam)
        {
            var procId=0;
            GetWindowThreadProcessId(hwnd, ref procId);
            if(procId==lParam)
            {
                var style = GetWindowLong(hwnd, GwlExstyle) & WsExAppwindow;  
                if(style>0)
                {
                    _targetHwnd = hwnd;
                    return false;
                }
            }
            return true;
        }

        
        public static IntPtr FindMainWindowByProc(string procName)
        {
            _targetHwnd = IntPtr.Zero;
            var process = Process.GetProcessesByName(procName);
            if(process.Length>0)
            {
                EnumWindows(new EnumWindowsProc(EnumWindowsProcessId), process[0].Id);
                return _targetHwnd;
            }
            return IntPtr.Zero;
        }

        public static void Show(IntPtr intPtr)
        {
            int style = GetWindowLong(intPtr, GwlExstyle) | WsExAppwindow;

            SetWindowLong(intPtr, GwlExstyle, style);

            ShowWindow(intPtr, ShowWindowCommands.Show);
        }

        public static void Hide(IntPtr intPtr)
        {
            int style = GetWindowLong(intPtr, GwlExstyle) & (~WsExAppwindow);


            SetWindowLong(intPtr, GwlExstyle, style);

            ShowWindow(intPtr, ShowWindowCommands.Hide);
        }
    }
}